const { ccclass, property } = cc._decorator;

@ccclass
export default class MathUtils {
    public static accAdd(e: number, t: number): number {
        let a, o, i = 0, r = 0;
        try {
            i = e.toString().split(".")[1].length;
        } catch (e) {
            i = 0;
        }
        try {
            r = t.toString().split(".")[1].length;
        } catch (e) {
            r = 0;
        }
        o = Math.abs(i - r);
        a = Math.pow(10, Math.max(i, r));
        if (o > 0) {
            const n = Math.pow(10, o);
            if (i > r) {
                e = Number(e.toString().replace(".", ""));
                t = Number(t.toString().replace(".", "")) * n;
            } else {
                e = Number(e.toString().replace(".", "")) * n;
                t = Number(t.toString().replace(".", ""));
            }
        } else {
            e = Number(e.toString().replace(".", ""));
            t = Number(t.toString().replace(".", ""));
        }
        return (e + t) / a;
    }

    public static accSub(e: number, t: number): number {
        let a, o = 0, i = 0;
        try {
            o = e.toString().split(".")[1].length;
        } catch (e) {
            o = 0;
        }
        try {
            i = t.toString().split(".")[1].length;
        } catch (e) {
            i = 0;
        }
        return Number(((e * (a = Math.pow(10, Math.max(o, i))) - t * a) / a).toFixed(o >= i ? o : i));
    }

    public static accMul(e: number, t: number): number {
        let a = 0, o = e.toString(), i = t.toString();
        try {
            a += o.split(".")[1].length;
        } catch (e) { }
        try {
            a += i.split(".")[1].length;
        } catch (e) { }
        return Number(o.replace(".", "")) * Number(i.replace(".", "")) / Math.pow(10, a);
    }

    public static accDiv(e: number, t: number): number {
        let a = 0, o = 0;
        try {
            a = e.toString().split(".")[1].length;
        } catch (e) { }
        try {
            o = t.toString().split(".")[1].length;
        } catch (e) { }
        return Number(e.toString().replace(".", "")) / Number(t.toString().replace(".", "")) * Math.pow(10, o - a);
    }

    public static NumberLerp(e: number, t: number, a: number): number {
        return e + (t - e) * a;
    }

    public static Ve3Lerp(e: cc.Vec3, t: cc.Vec3, a: number): cc.Vec3 {
        return new cc.Vec3(e.x + (t.x - e.x) * a, e.y + (t.y - e.y) * a);
    }

    public static Ve2Lerp(e: cc.Vec2, t: cc.Vec2, a: number): cc.Vec2 {
        return new cc.Vec2(e.x + (t.x - e.x) * a, e.y + (t.y - e.y) * a);
    }

    public static getAngle(e: number): number {
        return 180 * e / Math.PI;
    }

    public static getRadian(e: number): number {
        return e / 180 * Math.PI;
    }

    public static getRadian2(e: number, t: number, a: number, o: number): number {
        const i = a - e, r = o - t;
        return Math.atan2(r, i);
    }

    public static getDistance(e: cc.Vec2 | cc.Vec3, t: cc.Vec2 | cc.Vec3): number {
        const a = t.x - e.x, o = t.y - e.y, i = a * a + o * o;
        return Math.sqrt(i);
    }

    public static limit(e: number, t: number): number {
        e = Math.min(e, t);
        const a = (t = Math.max(e, t)) - e;
        return e + Math.random() * a;
    }

    public static limitInteger(e: number, t: number): number {
        return Math.round(this.limit(e, t));
    }

    public static randomArray<T>(e: T[]): T {
        return e[Math.floor(Math.random() * e.length)];
    }

    public static SagPoint(e: cc.Vec3, t: cc.Vec3, a: cc.Vec3, o: cc.Vec3): cc.Vec3 {
        const i = (a.x - o.x) * (a.x - o.x) + (a.y - o.y) * (a.y - o.y), r = ((e.x - a.x) * (o.x - a.x) + (e.y - a.y) * (o.y - a.y)) / i, n = a.x + r * (o.x - a.x), l = a.y + r * (o.y - a.y);
        return new cc.Vec3(n, l);
    }

    public static extendedLinePoint(e: cc.Vec2, t: cc.Vec2, a: number): cc.Vec3 {
        let o, i, r;
        o = this.getDistance(e, t);
        if (t.x > e.x && t.y > e.y) {
            i = a / o * Math.abs(e.x - t.x) + t.x;
            r = a / o * Math.abs(e.y - t.y) + t.y;
        } else if (t.x < e.x && t.y > e.y) {
            i = -a / o * Math.abs(e.x - t.x) + t.x;
            r = a / o * Math.abs(e.y - t.y) + t.y;
        } else if (t.x < e.x && t.y < e.y) {
            i = -a / o * Math.abs(e.x - t.x) + t.x;
            r = -a / o * Math.abs(e.y - t.y) + t.y;
        } else if (t.x > e.x && t.y < e.y) {
            i = a / o * Math.abs(e.x - t.x) + t.x;
            r = -a / o * Math.abs(e.y - t.y) + t.y;
        }
        return new cc.Vec3(i, r);
    }

    public static getTwoPointsRadian1(e: cc.Vec2, t: cc.Vec2): number {
        const a = Math.abs(e.x - t.x), o = Math.abs(e.y - t.y), i = o / Math.sqrt(Math.pow(a, 2) + Math.pow(o, 2)), r = Math.acos(i), n = Math.floor(180 / (Math.PI / r));
        t.x > e.x && t.y < e.y && (n = 180 - n);
        t.x == e.x && t.y > e.y && (n = 180);
        t.x > e.x && t.y == e.y && (n = 90);
        t.x < e.x && t.y < e.y && (n = 180 + n);
        t.x < e.x && t.y == e.y && (n = 270);
        t.x < e.x && t.y > e.y && (n = 360 - n);
        return n;
    }

    public static getTwoPointsRadian2(e: cc.Vec2, t: cc.Vec2): number {
        const a = e.x - t.x, o = e.y - t.y;
        return -180 * Math.atan2(o, a) / Math.PI - 90;
    }

    public static fingCrossPoint(e: cc.Vec2, t: cc.Vec2, a: cc.Vec2, o: cc.Vec2): cc.Vec3 {
        const i = t.y - e.y, r = e.x - t.x, n = e.x * t.y - t.x * e.y, l = o.y - a.y, s = a.x - o.x, c = a.x * o.y - o.x * a.y, u = i * s - l * r;
        if (0 == u) return null;
        const p = (n * s - c * r) / u, d = (i * c - l * n) / u;
        return new cc.Vec3(Math.floor(p), Math.floor(d));
    }

    public static getCenterPosition(e: cc.Vec2, t: cc.Vec2): cc.Vec2 {
        return cc.v2((e.x + t.x) / 2, (e.y + t.y) / 2);
    }

    public static getPosOnCircle(e: cc.Vec2, t: number, a: number): cc.Vec2 {
        const o = e.x + t * Math.cos(a * Math.PI / 180), i = e.y + t * Math.min(a * Math.PI / 180);
        return cc.v2(o, i);
    }

    public static CalculationMidPoint(e: cc.Vec2, t: cc.Vec2, a: number): cc.Vec2 {
        if (!e.x || !t) return cc.v2(0, 0);
        let o = e;
        if (e.x <= t.x && e.y <= t.y) {
            const i = t.x - e.x, r = t.y - e.y;
            o = cc.v2(e.x + i * a, e.y + r * a);
        } else if (e.x > t.x && e.y < t.y) {
            const i = t.x - e.x, r = t.y - e.y;
            o = cc.v2(e.x + i * a, e.y + r * a);
        } else if (e.x > t.x && e.y > t.y) {
            const i = t.x - e.x, r = t.y - e.y;
            o = cc.v2(e.x + i * a, e.y + r * a);
        } else if (e.x < t.x && e.y > t.y) {
            const i = t.x - e.x, r = t.y - e.y;
            o = cc.v2(e.x + i * a, e.y + r * a);
        }
        return o;
    }
}